home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / elv18src.zip / ex.c < prev    next >
C/C++ Source or Header  |  1994-01-21  |  21KB  |  869 lines

  1. /* ex.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains the code for reading ex commands. */
  12.  
  13. #include "config.h"
  14. #include "ctype.h"
  15. #include "vi.h"
  16.  
  17. /* the usual "min" macro.  Note that the minumum argument is evaluated twice. */
  18. #define MIN(a, b)    ((a)<=(b) ? (a) : (b))
  19.  
  20. /* This data type is used to describe the possible argument combinations */
  21. typedef short ARGT;
  22. #define FROM    1        /* allow a linespec */
  23. #define    TO    2        /* allow a second linespec */
  24. #define BANG    4        /* allow a ! after the command name */
  25. #define EXTRA    8        /* allow extra args after command name */
  26. #define XFILE    16        /* expand wildcards in extra part */
  27. #define NOSPC    32        /* no spaces allowed in the extra part */
  28. #define    DFLALL    64        /* default file range is 1,$ */
  29. #define DFLNONE    128        /* no default file range */
  30. #define NODFL    256        /* do not default to the current file name */
  31. #define EXRCOK    512        /* can be in a .exrc file */
  32. #define NL    1024        /* if mode!=MODE_EX, then write a newline first */
  33. #define PLUS    2048        /* allow a line number, as in ":e +32 foo" */
  34. #define ZERO    4096        /* allow 0 to be given as a line number */
  35. #define NOBAR    8192        /* treat following '|' chars as normal */
  36. #define FILES    (XFILE + EXTRA)    /* multiple extra files allowed */
  37. #define WORD1    (EXTRA + NOSPC)    /* one extra word allowed */
  38. #define FILE1    (FILES + NOSPC)    /* 1 file allowed, defaults to current file */
  39. #define NAMEDF    (FILE1 + NODFL)    /* 1 file allowed, defaults to "" */
  40. #define NAMEDFS    (FILES + NODFL)    /* multiple files allowed, default is "" */
  41. #define RANGE    (FROM + TO)    /* range of linespecs allowed */
  42. #define NONE    0        /* no args allowed at all */
  43.  
  44. /* This array maps ex command names to command codes. The order in which
  45.  * command names are listed below is significant -- ambiguous abbreviations
  46.  * are always resolved to be the first possible match.  (e.g. "r" is taken
  47.  * to mean "read", not "rewind", because "read" comes before "rewind")
  48.  */
  49. static struct
  50. {
  51.     char    *name;    /* name of the command */
  52.     CMD    code;    /* enum code of the command */
  53.     void    (*fn) P_((MARK, MARK, CMD, int, char *));
  54.             /* function which executes the command */
  55.     ARGT    argt;    /* command line arguments permitted/needed/used */
  56. }
  57.     cmdnames[] =
  58. {   /*    cmd name    cmd code    function    arguments */
  59.     {"print",    CMD_PRINT,    cmd_print,    RANGE+NL    },
  60.  
  61.     {"append",    CMD_APPEND,    cmd_append,    FROM+ZERO+BANG    },
  62. #ifdef DEBUG
  63.     {"bug",        CMD_DEBUG,    cmd_debug,    RANGE+BANG+EXTRA+NL},
  64. #endif
  65.     {"change",    CMD_CHANGE,    cmd_append,    RANGE+BANG    },
  66.     {"delete",    CMD_DELETE,    cmd_delete,    RANGE+WORD1    },
  67.     {"edit",    CMD_EDIT,    cmd_edit,    BANG+FILE1+PLUS    },
  68.     {"file",    CMD_FILE,    cmd_file,    NAMEDF        },
  69.     {"global",    CMD_GLOBAL,    cmd_global,    RANGE+BANG+EXTRA+DFLALL+NOBAR},
  70.     {"insert",    CMD_INSERT,    cmd_append,    FROM+BANG    },
  71.     {"join",    CMD_INSERT,    cmd_join,    RANGE+BANG    },
  72.     {"k",        CMD_MARK,    cmd_mark,    FROM+WORD1    },
  73.     {"list",    CMD_LIST,    cmd_print,    RANGE+NL    },
  74.     {"move",    CMD_MOVE,    cmd_move,    RANGE+EXTRA    },
  75.     {"next",    CMD_NEXT,    cmd_next,    BANG+NAMEDFS    },
  76.     {"Next",    CMD_PREVIOUS,    cmd_next,    BANG        },
  77.     {"quit",    CMD_QUIT,    cmd_xit,    BANG        },
  78.     {"read",    CMD_READ,    cmd_read,    FROM+ZERO+NAMEDF},
  79.     {"substitute",    CMD_SUBSTITUTE,    cmd_substitute,    RANGE+EXTRA+NOBAR},
  80.     {"to",        CMD_COPY,    cmd_move,    RANGE+EXTRA    },
  81.     {"undo",    CMD_UNDO,    cmd_undo,    NONE        },
  82.     {"vglobal",    CMD_VGLOBAL,    cmd_global,    RANGE+EXTRA+DFLALL+NOBAR},
  83.     {"write",    CMD_WRITE,    cmd_write,    RANGE+BANG+FILE1+DFLALL},
  84.     {"xit",        CMD_XIT,    cmd_xit,    BANG+NL        },
  85.     {"yank",    CMD_YANK,    cmd_delete,    RANGE+WORD1    },
  86.  
  87.     {"!",        CMD_BANG,    cmd_shell,    EXRCOK+RANGE+NAMEDFS+DFLNONE+NL+NOBAR},
  88.     {"\"",        CMD_COMMENT,    cmd_comment,    EXRCOK+BANG+EXTRA+NOBAR},
  89.     {"#",        CMD_NUMBER,    cmd_print,    RANGE+NL    },
  90.     {"<",        CMD_SHIFTL,    cmd_shift,    RANGE+EXTRA    },
  91.     {">",        CMD_SHIFTR,    cmd_shift,    RANGE+EXTRA    },
  92.     {"=",        CMD_EQUAL,    cmd_file,    RANGE        },
  93.     {"&",        CMD_SUBAGAIN,    cmd_substitute,    RANGE        },
  94.     {"~",        CMD_SUBAGAIN,    cmd_substitute,    RANGE        },
  95. #ifndef NO_AT
  96.     {"@",        CMD_AT,        cmd_at,        EXTRA        },
  97. #endif
  98.  
  99. #ifndef NO_ABBR
  100.     {"abbreviate",    CMD_ABBR,    cmd_map,    EXRCOK+BANG+EXTRA},
  101. #endif
  102. #ifndef NO_IF
  103.     {"and",        CMD_AND,    cmd_if,        EXRCOK+EXTRA    },
  104. #endif
  105.     {"args",    CMD_ARGS,    cmd_args,    EXRCOK+NAMEDFS    },
  106. #ifndef NO_ERRLIST
  107.     {"cc",        CMD_CC,        cmd_make,    BANG+FILES    },
  108. #endif
  109.     {"cd",        CMD_CD,        cmd_cd,        EXRCOK+BANG+NAMEDF},
  110.     {"copy",    CMD_COPY,    cmd_move,    RANGE+EXTRA    },
  111. #ifndef NO_DIGRAPH
  112.     {"digraph",    CMD_DIGRAPH,    cmd_digraph,    EXRCOK+BANG+EXTRA},
  113. #endif
  114. #ifndef NO_IF
  115.     {"else",    CMD_ELSE,    cmd_then,    EXRCOK+EXTRA+NOBAR },
  116. #endif
  117. #ifndef NO_ERRLIST
  118.     {"errlist",    CMD_ERRLIST,    cmd_errlist,    BANG+NAMEDF    },
  119. #endif
  120.     {"ex",        CMD_EDIT,    cmd_edit,    BANG+FILE1    },
  121. #ifndef NO_IF
  122.     {"if",        CMD_IF,        cmd_if,        EXRCOK+EXTRA    },
  123. #endif
  124.     {"mark",    CMD_MARK,    cmd_mark,    FROM+WORD1    },
  125. #ifndef NO_MKEXRC
  126.     {"mkexrc",    CMD_MKEXRC,    cmd_mkexrc,    NAMEDF        },
  127. #endif
  128.     {"number",    CMD_NUMBER,    cmd_print,    RANGE+NL    },
  129. #ifndef NO_IF
  130.     {"or",        CMD_OR,        cmd_if,        EXRCOK+EXTRA    },
  131. #endif
  132. #ifndef NO_TAGSTACK
  133.     {"pop",        CMD_POP,    cmd_pop,    BANG+WORD1    },
  134. #endif
  135.     {"put",        CMD_PUT,    cmd_put,    FROM+ZERO+WORD1    },
  136.     {"set",        CMD_SET,    cmd_set,    EXRCOK+EXTRA    },
  137.     {"shell",    CMD_SHELL,    cmd_shell,    NL        },
  138.     {"source",    CMD_SOURCE,    cmd_source,    EXRCOK+NAMEDF    },
  139. #ifdef SIGTSTP
  140.     {"stop",    CMD_STOP,    cmd_suspend,    NONE        },
  141. #endif
  142.     {"tag",        CMD_TAG,    cmd_tag,    BANG+WORD1    },
  143. #ifndef NO_IF
  144.     {"then",    CMD_THEN,    cmd_then,    EXRCOK+EXTRA+NOBAR },
  145. #endif
  146.     {"version",    CMD_VERSION,    cmd_version,    EXRCOK+NONE    },
  147.     {"visual",    CMD_VISUAL,    cmd_edit,    BANG+NAMEDF    },
  148.     {"wq",        CMD_WQUIT,    cmd_xit,    NL+BANG        },
  149.  
  150. #ifdef DEBUG
  151.     {"debug",    CMD_DEBUG,    cmd_debug,    RANGE+BANG+EXTRA+NL},
  152.     {"validate",    CMD_VALIDATE,    cmd_validate,    BANG+NL        },
  153. #endif
  154.     {"chdir",    CMD_CD,        cmd_cd,        EXRCOK+BANG+NAMEDF},
  155. #ifndef NO_COLOR
  156.     {"color",    CMD_COLOR,    cmd_color,    EXRCOK+EXTRA    },
  157. #endif
  158. #ifndef NO_ERRLIST
  159.     {"make",    CMD_MAKE,    cmd_make,    BANG+NAMEDFS    },
  160. #endif
  161.     {"map",        CMD_MAP,    cmd_map,    EXRCOK+BANG+EXTRA},
  162.     {"previous",    CMD_PREVIOUS,    cmd_next,    BANG        },
  163.     {"rewind",    CMD_REWIND,    cmd_next,    BANG        },
  164. #ifdef SIGTSTP
  165.     {"suspend",    CMD_SUSPEND,    cmd_suspend,    NONE        },
  166. #endif
  167.     {"unmap",    CMD_UNMAP,    cmd_map,    EXRCOK+BANG+EXTRA},
  168. #ifndef NO_ABBR
  169.     {"unabbreviate",CMD_UNABBR,    cmd_map,    EXRCOK+EXTRA    },
  170. #endif
  171.  
  172.     {(char *)0}
  173. };
  174.  
  175.  
  176. /* This function parses a search pattern - given a pointer to a / or ?,
  177.  * it replaces the ending / or ? with a \0, and returns a pointer to the
  178.  * stuff that came after the pattern.
  179.  */
  180. char    *parseptrn(ptrn)
  181.     REG char    *ptrn;
  182. {
  183.     REG char     *scan;
  184.  
  185.     for (scan = ptrn + 1;
  186.          *scan && *scan != *ptrn;
  187.          scan++)
  188.     {
  189.         /* allow backslashed versions of / and ? in the pattern */
  190.         if (*scan == '\\' && scan[1] != '\0')
  191.         {
  192.             scan++;
  193.             if (*scan == '[' && scan[1] != '\0')    /*-g.t.*/
  194.             {                    /*-g.t.*/
  195.                 scan++;                /*-g.t.*/
  196.             }                    /*-g.t.*/
  197.         }
  198.         /* allow / and ? between [ and ] */        /*-g.t.*/
  199.         if (*scan == '[' && scan[1] != '\0')        /*-g.t.*/
  200.         {                        /*-g.t.*/
  201.             scan++;                    /*-g.t.*/
  202.             while (*scan != ']' && scan[1] != '\0')    /*-g.t.*/
  203.             {                    /*-g.t.*/
  204.                 scan++;                /*-g.t.*/
  205.             }                    /*-g.t.*/
  206.         }
  207.     }
  208.     if (*scan)
  209.     {
  210.         *scan++ = '\0';
  211.     }
  212.  
  213.     return scan;
  214. }
  215.  
  216.  
  217. /* This function parses a line specifier for ex commands */
  218. char *linespec(s, markptr)
  219.     REG char    *s;        /* start of the line specifier */
  220.     MARK        *markptr;    /* where to store the mark's value */
  221. {
  222.     long        num;
  223.     REG char    *t;
  224.  
  225.     /* parse each ;-delimited clause of this linespec */
  226.     do
  227.     {
  228.         /* skip an initial ';', if any */
  229.         if (*s == ';')
  230.         {
  231.             s++;
  232.         }
  233.  
  234.         /* skip leading spaces */
  235.         while (isspace(*s))
  236.         {
  237.             s++;
  238.         }
  239.  
  240.         /* dot means current position */
  241.         if (*s == '.')
  242.         {
  243.             s++;
  244.             *markptr = cursor;
  245.         }
  246.         /* '$' means the last line */
  247.         else if (*s == '$')
  248.         {
  249.             s++;
  250.             *markptr = MARK_LAST;
  251.         }
  252.         /* digit means an absolute line number */
  253.         else if (isdigit(*s))
  254.         {
  255.             for (num = 0; isdigit(*s); s++)
  256.             {
  257.                 num = num * 10 + *s - '0';
  258.             }
  259.             *markptr = MARK_AT_LINE(num);
  260.         }
  261.         /* appostrophe means go to a set mark */
  262.         else if (*s == '\'')
  263.         {
  264.             s++;
  265.             *markptr = m_tomark(cursor, 1L, (int)*s);
  266.             s++;
  267.         }
  268.         /* slash means do a search */
  269.         else if (*s == '/' || *s == '?')
  270.         {
  271.             /* put a '\0' at the end of the search pattern */
  272.             t = parseptrn(s);
  273.  
  274.             /* search for the pattern */
  275.             *markptr &= ~(BLKSIZE - 1);
  276.             if (*s == '/')
  277.             {
  278.                 pfetch(markline(*markp